package com.orange.core.service.employee;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orange.core.mapper.employee.EmployeeCardMapper;
import com.orange.core.mapper.shop.ShopMapper;
import com.orange.core.mapper.user.UserMapper;
import com.orange.core.pojo.PageReqDto;
import com.orange.core.pojo.entity.employee.EmployeeCard;
import com.orange.core.pojo.entity.shop.Shop;
import com.orange.core.pojo.entity.user.User;
import com.orange.core.pojo.enums.EUserType;
import com.orange.core.pojo.enums.EWriteOffType;
import com.orange.core.pojo.req.employee.EmployeeCardPageReq;
import com.orange.core.pojo.req.employee.EmployeeCardSaveReq;
import com.orange.core.pojo.req.writeoff.WriteOffSaveReq;
import com.orange.core.pojo.rsp.writeoff.WriteOffResultRsp;
import com.orange.core.service.writeoff.WriteOffSaveService;
import com.orange.core.util.PrincipalUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class EmployeeCardService extends ServiceImpl<EmployeeCardMapper, EmployeeCard> {

    private final WriteOffSaveService writeOffSaveService;
    private final UserMapper userMapper;
    private final ShopMapper shopMapper;

    public Page<EmployeeCard> page(@RequestBody PageReqDto<EmployeeCardPageReq> req) {
        EmployeeCardPageReq condition = req.getCondition();
        if (condition == null) {
            condition = new EmployeeCardPageReq();
        }
        Page<EmployeeCard> page = this.lambdaQuery()
                .eq(condition.getEmployeeId() != null, EmployeeCard::getEmployeeId, condition.getEmployeeId())
                .page(req.toPage());
        List<EmployeeCard> records = page.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            List<Integer> userIds = records.stream().map(EmployeeCard::getEmployeeId).toList();
            Map<Integer, User> employeeMap = userMapper.selectBatchIds(userIds).stream().collect(Collectors.toMap(User::getId, Function.identity()));
            for (EmployeeCard employeeCard : records) {
                User user = employeeMap.get(employeeCard.getEmployeeId());
                employeeCard.setEmployeeNo(user.getUserNo());
                employeeCard.setEmployeeName(user.getNickname());
            }
        }
        return page;
    }

    @Transactional
    public boolean save(EmployeeCardSaveReq req) {
        User user = userMapper.selectById(req.getEmployeeId());
        Assert.isTrue(EUserType.EMPLOYEE_TYPES.contains(user.getType()), "只能给员工添加员工卡");

        String cardNo;
        EmployeeCard employeeCard;
        do {
            cardNo = RandomStringUtils.randomNumeric(8);
            employeeCard = this.lambdaQuery()
                    .eq(EmployeeCard::getCardNo, cardNo)
                    .one();
        } while (employeeCard != null);

        employeeCard = new EmployeeCard();
        employeeCard.setShopId(req.getShopId());
        employeeCard.setEmployeeId(req.getEmployeeId());
        employeeCard.setCardNo(cardNo);
        return super.save(employeeCard);
    }

    @Transactional
    public boolean change(EmployeeCardSaveReq req) {
        this.remove(new LambdaQueryWrapper<EmployeeCard>()
                .eq(EmployeeCard::getEmployeeId, req.getEmployeeId()));
        return save(req);
    }

    @Transactional
    public boolean unbind(int userId) {
        User user = new User();
        user.setId(userId);
        user.setType(EUserType.USER.getValue());
        userMapper.updateById(user);

        this.remove(new LambdaQueryWrapper<EmployeeCard>()
                .eq(EmployeeCard::getEmployeeId, userId));
        return true;
    }

    @Transactional
    public WriteOffResultRsp writeOff(String writeOffNo) {
        EmployeeCard employeeCard = this.lambdaQuery()
                .eq(EmployeeCard::getCardNo, writeOffNo)
                .one();
        Assert.notNull(employeeCard, "员工卡不存在");

        User merchant = userMapper.selectById(PrincipalUtil.getId());
        Shop shop = shopMapper.selectById(merchant.getShopId());
        writeOffSaveService.writeOff(WriteOffSaveReq.builder()
                .businessId(Integer.parseInt(RandomStringUtils.randomNumeric(8)))
                .businessType(EWriteOffType.EMPLOYEE_CARD.getValue())
                .userId(employeeCard.getEmployeeId())
                .shopId(shop.getId())
                .build());

        return WriteOffResultRsp.builder()
                .build();
    }

    @Transactional
    public void updateEmployeeCard(int employeeId, int type, Integer shopId, User dbUser) {
        if (EUserType.USER.getValue() == type && !Objects.equals(dbUser.getType(), EUserType.USER.getValue())) {
            // 普通用户，但原来不是普通用户，作废员工卡
            unbind(employeeId);
        } else if (EUserType.EMPLOYEE_TYPES.contains(type) && !EUserType.EMPLOYEE_TYPES.contains(dbUser.getType())) {
            // 员工，但原来不是员工，发卡
            this.save(EmployeeCardSaveReq.builder()
                    .employeeId(employeeId)
                    .shopId(shopId)
                    .build());
        } else if (EUserType.EMPLOYEE_TYPES.contains(type) && EUserType.EMPLOYEE_TYPES.contains(dbUser.getType())) {
            User user = userMapper.selectById(employeeId);
            if (!Objects.equals(user.getShopId(), dbUser.getShopId())) {
                // 换品牌了，换卡
                change(EmployeeCardSaveReq.builder()
                        .employeeId(employeeId)
                        .shopId(shopId)
                        .build());
            }
        }
    }
}
